package com.nannybear.Controller;

import android.os.Handler;
import android.widget.ImageButton;

import java.util.Observable;
import java.util.Observer;

/**
 * \brief Manage the thresholds received and change the view
 * \author Audrey LOISEAU
 * \date 6-04-2015
 */

/********************************* COPYRIGHT *********************************
 * Copyright (c) 2015, Audrey LOISEAU and Benjamin LANCINOT.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *************************************************************************************/

public class CriticalityThresholds implements Observer{
    /********** DECLARATIONS **********/
    // Variables
    static private final int NORMAL = 1;
    static private final int MODERATE_COLD = 2;
    static private final int MODERATE_HOT = 3;
    static private final int CRITICAL_COLD = 4;
    static private final int CRITICAL_HOT = 5;
    private boolean timerTempActivated;
    private boolean timerHumActivated;

    // Class
    private final ViewPuppeteer viewPuppeteer;

    // Handler
    private final Handler myHandler = new Handler();
    private final Handler myTimer = new Handler();

    /************ METHODS ************/
    /**
     * \brief Constructor
     * \param viewPuppeteer The ViewPuppeteer class
     */
    public CriticalityThresholds(ViewPuppeteer viewPuppeteer){
        this.viewPuppeteer = viewPuppeteer;
        timerTempActivated = false;
        timerHumActivated = false;
    }

    /**
     * \brief Inform the good screen of a warning
     * \param warning   The threshold (\e string)
     * \param isTemp    True if it's a temperature warning, else it is a Humidity warning
     */
    private void changeWarning(String warning, boolean isTemp){
        if(isTemp) {
            if (this.getViewPuppeteer().getmActivity().getCurrentScreen() == this.getViewPuppeteer().getmActivity().getTempScreen()) {
                this.getViewPuppeteer().getmActivity().getTempScreen().changeToWarn(warning);
            }
            if(this.getViewPuppeteer().getmActivity().getCurrentScreen() == this.getViewPuppeteer().getmActivity().getHomeScreen()){
                this.getViewPuppeteer().getmActivity().getHomeScreen().changeToWarnTemp(warning);
            }
        }else{
            if(this.getViewPuppeteer().getmActivity().getCurrentScreen() == this.getViewPuppeteer().getmActivity().getHumidityScreen()){
                this.getViewPuppeteer().getmActivity().getHumidityScreen().changeToWarn(warning);
            }
            if(this.getViewPuppeteer().getmActivity().getCurrentScreen() == this.getViewPuppeteer().getmActivity().getHomeScreen()){
                this.getViewPuppeteer().getmActivity().getHomeScreen().changeToWarnHum(warning);
            }
        }
    }

    /**
     * \brief Display a pop up for the critical thresholds
     */
    void displayPopUp(){
        int kindPopUp = 1; // threshold
        String title = "BE CAREFUL";
        String message = null;
        String button = "OK";
        if(isTimerTempActivated() && !isTimerHumActivated()){
            message = "Temperature is in a critical state.\nIf you want more information go on the temperature tab.";
        }
        if(!isTimerTempActivated() && isTimerHumActivated()){
            message = "Humidity is in a critical state.\nIf you want more information go on the humidity tab.";
        }
        if(isTimerTempActivated() && isTimerHumActivated()){
            message = "Humidity and temperature are in a critical state.\nIf you want more information go on the appropriate tabs.";
        }
        this.getViewPuppeteer().displayPopUp(kindPopUp, title, message, button);
    }

    /**
     * \brief Timer for the pop-up
     */
    public void startTimer(){
        final Runnable tempTimer = new Runnable() {
            @Override
            public void run() {
                displayPopUp();
            }
        };
        // Wait for 300000 ms = 5 min
        myTimer.postDelayed(tempTimer, 300000);
    }

    /**
     * \brief Display a pop-up for the critical threshold
     * \param threshold The value of the threshold
     */
    void displayHandlerPopup(final double threshold){
        myHandler.post(new Runnable() {
            @Override
            public void run() {
                if (threshold == CRITICAL_COLD || threshold == CRITICAL_HOT ) {
                    displayPopUp();
                }
                else {
                    myTimer.removeCallbacksAndMessages(null);
                }
            }
        });
    }

    /**
     * \brief Manage the timer and ask to change the warnings for the temperature
     * \param thresholdTemp     The value of the temperature threshold
     */
    void changeConcerningTemp(final double thresholdTemp){
        myHandler.post(new Runnable() {
            @Override
            public void run() {
                if (thresholdTemp == NORMAL) {
                    setTimerTempActivated(false);
                    changeWarning(" perfect", true);
                }
                if (thresholdTemp == MODERATE_COLD) {
                    setTimerTempActivated(false);
                    changeWarning(" too cold", true);
                }
                if (thresholdTemp == MODERATE_HOT) {
                    setTimerTempActivated(false);
                    changeWarning(" too hot", true);
                }
                if (thresholdTemp == CRITICAL_COLD) {
                    setTimerTempActivated(true);
                    changeWarning(" too cold", true);
                }
                if (thresholdTemp == CRITICAL_HOT) {
                    setTimerTempActivated(true);
                    changeWarning(" too hot", true);
                }
                changeTabsThreshold((int)thresholdTemp, true);
            }
        });
    }

    /**
     * \brief Manage the timer and ask to change the warnings for the humidity
     * \param thresholdHum     The value of the humidity threshold
     */
    void changeConcerningHum(final double thresholdHum){
        myHandler.post(new Runnable() {
            @Override
            public void run() {
                if (thresholdHum == NORMAL) {
                    setTimerHumActivated(false);
                    changeWarning(" perfect", false);
                }
                if (thresholdHum == MODERATE_COLD) {
                    setTimerHumActivated(false);
                    changeWarning(" too dry", false);
                }
                if (thresholdHum == MODERATE_HOT) {
                    setTimerHumActivated(false);
                    changeWarning(" too wet", false);
                }
                if (thresholdHum == CRITICAL_COLD) {
                    setTimerHumActivated(true);
                    changeWarning(" too dry", false);
                }if (thresholdHum == CRITICAL_HOT) {
                    setTimerHumActivated(true);
                    changeWarning(" too wet", false);
                }
                changeTabsThreshold(thresholdHum, false);
            }
        });
    }

    /**
     * \brief Change the tab
     * \param button    The button to change
     * \param drawable  The drawable of the button
     */
    private void changeTab(final ImageButton button, final int drawable){
        myHandler.post(new Runnable() {
            @Override
            public void run() {
                button.setBackgroundResource(drawable);
            }
        });
    }

    /**
     * \brief Give the index of the threshold
     * \param threshold The value of the threshold
     * \return  The value of the drawable
     */
    private int returnIndexOfThreshold(double threshold){
        if (threshold ==  MODERATE_COLD ||threshold ==  MODERATE_HOT ){
           return 1;
        }else if(threshold ==  CRITICAL_COLD ||threshold ==  CRITICAL_HOT ){
           return 2;
        }else{
           return 0;
        }
    }

    /**
     * \brief Ask to change the tab with the good drawable
     * \param threshold   The value of threshold
     * \param isTemp    True if is a temperature threshold, else is a humidity value
     */
    private void changeTabsThreshold(double threshold, boolean isTemp){
        int i = returnIndexOfThreshold(threshold);
        if(isTemp){
          changeTab(this.viewPuppeteer.getmActivity().getCurrentScreen().getTempButton(), this.viewPuppeteer.getmActivity().getCurrentScreen().getTempDrawable()[i]);
        }else{
          changeTab(this.viewPuppeteer.getmActivity().getCurrentScreen().getHumidityButton(), this.viewPuppeteer.getmActivity().getCurrentScreen().getHumDrawable()[i]);
        }
    }

    /**
     * \brief Reception of a new threshold
     * \param obs Observable class
     * \param obj The value of threshold
     */
    public void update(Observable obs, Object obj){
        if(!obj.toString().equals("")) {
            Double valueThreshold = Double.parseDouble(obj.toString());
            String name = obs.getClass().getSimpleName();
            if (name.equalsIgnoreCase("TemperatureThreshold")) {
                changeConcerningTemp(valueThreshold);
                displayHandlerPopup(valueThreshold);
            }
            if (name.equalsIgnoreCase("HumidityThreshold")) {
                changeConcerningHum(valueThreshold);
                displayHandlerPopup(valueThreshold);
            }
        }
    }

    /*********** ACCESSORS ***********/
    /**
     * \brief Get method for the ViewPuppeteer class
     */
    ViewPuppeteer getViewPuppeteer() {
        return viewPuppeteer;
    }

    /**
     * \brief Get method for the activation of temperature timer
     */
    boolean isTimerTempActivated() {
        return timerTempActivated;
    }

    /**
     * \brief Get method for the activation of humidity timer
     */
    boolean isTimerHumActivated() {
        return timerHumActivated;
    }

    /**
     * \brief Get method for the timer
     */
    public Handler getMyTimer() {
        return myTimer;
    }

    /**
     * \brief Set method for the activation of temperature timer
     */
    void setTimerTempActivated(boolean timerTempActivated) {
        this.timerTempActivated = timerTempActivated;
    }

    /**
     * \brief Set method for the activation of humidity timer
     */
    void setTimerHumActivated(boolean timerHumActivated) {
        this.timerHumActivated = timerHumActivated;
    }
}
